//I/O => wait + copy
#include <iostream>
#include <cstring>
#include <cerrno>
#include <algorithm>
#include <vector>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/select.h>
// global variable
static const int max_capacity = sizeof(fd_set);
static int max_fd = 0;

// container
std::vector<int> fd_vector;

// socket
static int get_socket_fd()
{
    // socket
    int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_fd < 0)
    {
        std::cerr << strerror(errno) << std::endl;
        exit(1);
    }
    // info
    sockaddr_in my_addr;
    bzero(&my_addr, sizeof(sockaddr_in));
    my_addr.sin_family = AF_INET;
    my_addr.sin_addr.s_addr = INADDR_ANY;
    my_addr.sin_port = htons(8083);
    // bind
    if (bind(socket_fd, (sockaddr *)&my_addr, sizeof(sockaddr_in)) == -1)
    {
        std::cerr << strerror(errno) << std::endl;
        exit(2);
    }
    return socket_fd;
}

// handler
static bool accept_handler(const int listen_fd)
{
    sockaddr_in peer_addrin;
    socklen_t addr_len = sizeof(sockaddr_in);
    int new_fd = accept(listen_fd, (sockaddr *)&peer_addrin, &addr_len);
    if (new_fd < 0)
    {
        std::cerr << strerror(errno) << std::endl;
        exit(3);
    }
    fd_vector.push_back(new_fd);
    // adjust max_fd
    fd_vector.back() > max_fd ? max_fd = fd_vector.back() : 1;
    return new_fd;
}
static bool read_copy_handler(const int socket_fd)
{
    const int buffer_size = 1024;
    char buffer[buffer_size];
    bzero(buffer, buffer_size);
    ssize_t read_size = read(socket_fd, buffer, buffer_size);
    if (read_size == 0)
    {
        fd_vector.erase(std::find(fd_vector.begin(), fd_vector.end(), socket_fd));
    }
    std::cout << std::string(buffer);
}

// main
int main()
{
    int listen_fd = get_socket_fd();
    fd_vector.push_back(listen_fd);
    max_fd = listen_fd;
    listen(listen_fd, 5);
    while (true)
    {
        // set fd to wait
        fd_set fd_bitmap;
        FD_ZERO(&fd_bitmap);
        for (auto &e : fd_vector)
        {
            if (e >= 0)
                FD_SET(e, &fd_bitmap);
        }
        // set time to wait
        timeval wait_time{5, 0};
        // select
        int ready_num = select(max_fd+1, &fd_bitmap, nullptr, nullptr, &wait_time);
        if (ready_num == 0)
        {
            // other work...
            continue;
        }
        if (ready_num < 0)
        {
            // error
            std::cerr << strerror(errno) << std::endl;
            exit(4);
        }
        else
        {
            // event
            if (FD_ISSET(listen_fd, &fd_bitmap))
                accept_handler(listen_fd);
            else
            {
                for (int i = 1; i < fd_vector.size(); i++)
                {
                    if (FD_ISSET(fd_vector[i], &fd_bitmap))
                    {
                        read_copy_handler(fd_vector[i]);
                    }
                }
            }
        }
    }

    close(listen_fd);
    return 0;
}